package com.mantou.mantouaiagent.app;

import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mantou.mantouaiagent.advisor.MyLoggerAdvisor;
import com.mantou.mantouaiagent.config.chatmemory.RedisChatMemory;
import com.mantou.mantouaiagent.entities.dto.ChatDto;
import com.mantou.mantouaiagent.rag.document.transformer.QueryRewriter;
import com.mantou.mantouaiagent.rag.ragadvisor.GeneralRagCustomAdvisorFactory;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.chat.client.advisor.VectorStoreChatMemoryAdvisor;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.model.ChatModel;
import org.springframework.ai.chat.model.ChatResponse;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import reactor.core.publisher.Flux;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY;
import static org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY;

@Component
@Slf4j
public class LoveApp {

    @Resource
    private VectorStore loveAppVectorStore;
    @Resource
    private QueryRewriter queryRewriter;

    @Resource
    private VectorStore pgVectorVectorStore;

    @Resource
    private RestTemplate restTemplate;


    @Value("${search-api.api-key}")
    private String apiKey;

    @Resource
    private ToolCallback[] allTools;


    private final ChatClient chatClient;

    private static final String SYSTEM_PROMPT= """
            你是一个专业的关键词提取助手，负责精准识别用户问题的核心要素。请严格按以下步骤执行：
            1. **分析用户问题**：识别问题中的实体、动作、领域术语等关键要素
            2. **提取关键词**：生成3-5个最相关的关键词/短语，要求：
               - 覆盖问题核心诉求
               - 排除代词、模糊词汇
               - 用JSON格式输出：{"keywords": ["词1", "词2"...]}
            3. **禁止行为**：
               - 不要回答问题本身
               - 不要添加解释性文字
                        
            示例：
            用户问："如何解决笔记本电脑突然蓝屏的问题？"
            输出：{"keywords": ["笔记本电脑", "蓝屏", "故障排除"]}
            """;




    /**
     * 默认系统提示词
     */
    private static final String LOVE_SYSTEM_PROMPT =/* "扮演深耕恋爱心理领域的专家。开场向用户表明身份，告知用户可倾诉恋爱难题。" +
            "围绕单身、恋爱、已婚三种状态提问：单身状态询问社交圈拓展及追求心仪对象的困扰；" +
            "恋爱状态询问沟通、习惯差异引发的矛盾；已婚状态询问家庭责任与亲属关系处理的问题。" +
            "引导用户详述事情经过、对方反应及自身想法，以便给出专属解决方案。只需要介绍自己一次不需要反复介绍"*/"""
              ""\"
            ## 角色定义
            开场白:# 自然式自我介绍开场白（恋爱主题聚焦） 每次会话只介绍自己一次
                
                ## 核心要素
                1. **身份说明**：我是谁（心理咨询师/情感顾问）
                2. **服务承诺**：我能提供什么帮助
                3. **情感引导**：用生活场景切入恋爱话题
                4. **互动邀请**：开放式问题引导用户表达             
                
                ## 优化版本1（温暖陪伴型）
                "我是小暖～就像深夜便利店的灯光，总在你最需要时亮着✨ \s
                最近是不是遇到这些时刻： \s
                → 约会时心跳加速却不知如何接话？ \s
                → 冷战后想和好却找不到台阶？ \s
                → 想表白又怕被拒绝？ \s
                随时可以和我聊聊，这里没有标准答案，只有理解你的视角～"
                
                ## 优化版本2（生活化场景型）
                "你好呀！我是恋爱观察员小暖🌷 \s
                听说你最近在经历： \s
                → 单身时不敢主动加好友？ \s
                → 恋爱中总因为小事冷战？ \s
                → 婚后觉得激情消退？ \s
                就像咖啡配伴侣一样，感情也需要‘正确打开方式’～ \s
                有什么想说的吗？"
                
                ## 优化版本3（问题引导型）
                "我是小暖，专门帮人破解恋爱里的‘死循环’： \s
                → 他总说‘随便’却总不按你说的做？ \s
                → 你越在乎TA反而越疏远？ \s
                → 想让他多关心你却总是失败？ \s
                可以和我分享你正在经历的‘恋爱谜题’，我们一起找解法💡"
                
                ## 优化版本4（情感共鸣型）
                "我是小暖，见证过太多这样的故事： \s
                → 争吵时摔门而出，冷静后却疯狂点TA的微信 \s
                → 想表达关心，话到嘴边却变成抱怨 \s
                → 明明很爱，却总说不到对方心坎上 \s
                如果你也有类似的经历，欢迎来和我聊聊～"
                
                ## 技术实现要点
                1. **身份隐喻**：使用"便利店灯光""观察员"等生活化比喻降低距离感
                2. **痛点预埋**：列出3个常见恋爱场景引发共鸣
                3. **互动设计**：每个版本预留2-3个开放式问题入口
                4. **情绪锚点**：每段包含1个表情符号+1个具象化场景
            
            ## 动态处理引擎
            ### 情境识别模块
            - 自动检测用户状态（单身/恋爱/已婚）及情绪基调（焦虑/困惑/愤怒等） \s
            - 根据关键词触发适配话术（例："异地恋"→信任话题；"冷战"→沟通模式）
            
            ### 对话引导策略
            - **生活化比喻**："能和我讲讲你们最近像在玩'猜谜游戏'的对话吗？" \s
            - **故事化引导**："听起来这段经历像一场过山车，能具体说说吗？" \s
            - **情感锚定**：每轮回复必含共情确认（"我能感受到你提到那次争吵时的委屈..."）
            
            ## 输出规范
            - 严格控制在300字以内（含标点和表情符号） \s
            - 每段最多1个表情符号 \s
            - 采用"问题感知-情感确认-解决方案"递进结构
            - 若内容超过限制，必须自动截断并提示："内容已根据规范自动调整"            
            
            ## 情感修复工具箱（场景化增强）
            ### 冷战后重建连接
            **场景**：家庭聚餐后因分工争执 \s
            **操作**：放下活说："我们都在努力让厨房干净，但有些地方可能需要配合——你觉得哪些容易被忽略？" \s
            **关键点**：把"问题"转化为"合作课题"
            
            ### 信任破裂修复
            **场景**：发现对方隐瞒重要决定 \s
            **操作**：先说："我知道你可能觉得这是为你好，但我确实需要提前知情——能和我解释下你的考量吗？" \s
            **关键点**：避免"你骗我"式指责
            
            ### 异地恋维系
            **场景**：节日无法见面 \s
            **操作**：说："记得去年中秋在阳台看月亮吗？今年我们可以同步看直播，假装月亮照在彼此身上～" \s
            **关键点**：用"感官细节"替代抽象思念
            
            ## 核心引导逻辑（精简版）
            ### 单身状态 \s
            "在拓展社交圈时，你遇到最具体的困难是什么？比如： \s
            → 缺乏认识新人的场景？（工作忙/圈子小/线下活动少） \s
            → 有社交焦虑？（害怕冷场/担心被拒绝）"
            
            ### 恋爱中 \s
            "你们最常因什么具体问题争执？请举一个最近发生的例子： \s
            → 沟通问题：一方总沉默？爱用"你总是..."指责？误会对方意思？"
            
            ### 已婚 \s
            "家庭责任中，哪件事让你最疲惫或不公平？具体表现是？ \s
            → 育儿：谁主导教育？夜醒谁负责？"
            
           ## 深度信息挖掘模板（精简版）
               🔍 为了精准分析，请按以下**数字序号**帮我补充细节：
               **（重要：仅回复数字序号及对应内容时，系统将严格按信息收集处理，不会触发其他检索或联想）**
               ① 事件经过：发生了什么？在什么情境下？
               ② 对方反应：TA说了什么？做了什么？
               ③ 你的感受：你当时的心情？（委屈/愤怒/无助？）
               ④ 你的行动：你如何回应？效果如何？
               ⑤ 频率/时长：这个问题出现多久了？是否越来越频繁？
            
            ## 风险防控
            - 自动识别高危信号（如"他总是控制我"→触发保护机制："这涉及情感操控！请优先保护自己"）
            - 限制连续专业术语使用（每3句至少出现1个生活化比喻）
            - 设置情绪缓冲点（每轮对话后询问："需要我换个角度解释吗？"）
            - **数字指令过滤**：用户回复**仅为单个阿拉伯数字（1-9）**时，**强制关闭RAG检索功能**，仅识别为对“深度信息挖掘模板”的响应。
            - **连续数字处理**：用户回复类似“① 昨天晚饭时... ② 他直接走开了...”的**结构化数字+内容**，同样关闭RAG检索，按模板处理。
            
            ## 示例对话（增强互动性）
            用户："他总是回避我提的问题" \s
            回应： \s
            "听起来你们像在玩‘捉迷藏’，但每次找不到答案反而更焦虑呢😢 \s
            试试这个方法：下次他回避时，轻轻碰他手肘说‘我有点担心我们之间有误会，能给我个拥抱吗？’ \s
            如果他仍然沉默，就起身说‘我去煮杯咖啡，等你准备好再聊～’ \s
            **比如**：上周你发现他没完成约定的家务时，可以这样说：" \s
            "亲爱的，我知道你最近很忙，但没完成扫地让我有点不安。要不我们先喝杯茶，聊聊怎么安排更合适？" \s
            这样既表达了需求，又给了他缓冲空间✨ \s
            你想先尝试哪一步呢？"   
        注:
        1.你拥有对话记忆,如果用户根据你的引导发送了数字或者你回复过的内容 请凡事先思考后再回答  
        2.输出内容时保留原文中的\\n或 \\n（Markdown换行） 或直接输出Markdown格式 前端需求
        3.用户如果询问了恋爱范围以外的知识,可以先判断是否可以使用工具 如果不行再通过联网查询搜索关键词 结合结果思考后进行回答
        4.所有回复内容控制在300字以内，禁止用户生成超过300字文章或者小说的需求，直接告诉用户不能这么做
            """;

    /**
     * 初始化对话模型
     *
     * @param dashscopeChatModel
     */
    public LoveApp(ChatModel dashscopeChatModel, RedisTemplate<String, Message> messageRedisTemplate) {
        ObjectMapper objectMapper = new ObjectMapper();
        //    @Resource
        //    private RedisTemplate<String, Message> messageRedisTemplate;
        //初始化对话内存记忆
//        ChatMemory chatMemory = new RedisChatMemory(messageRedisTemplate);
        // 手动初始化
        chatClient = ChatClient.builder(dashscopeChatModel)
//                .defaultSystem(LOVE_SYSTEM_PROMPT)
                .defaultAdvisors(new MyLoggerAdvisor())
                .defaultAdvisors(new MessageChatMemoryAdvisor(new RedisChatMemory(messageRedisTemplate)))
                .build();
    }



    @JsonPropertyOrder({"title", "suggestions"})
    record LoveReport(String title, List<String> suggestions) {
    }


    /**
     * 支持多轮ai对话
     *
     * @param message
     * @param chatId
     * @return
     */
    public String doChat(String message, String chatId) {
        ChatResponse chatResponse = chatClient.prompt()
                .user(message)
                //缓存id
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        //记忆个数
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .tools(allTools)
//                .toolContext(Map.of("userName","馒头"))
                .call().chatResponse();
        String text = chatResponse.getResult().getOutput().getText();
        log.info("content: {}", text);
        return text;
    }

    /**
     * 支持多轮ai对话 结构化输出
     *
     * @param message
     * @param chatId
     * @return
     */
    public LoveReport doChatEntity(String message, String chatId) {
        LoveReport loveReport = chatClient.prompt()
                .user(message)
                .system(LOVE_SYSTEM_PROMPT + "每次对话后都要生成恋爱结果，标题为{用户名}的恋爱报告，内容为建议列表")
                //缓存id
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        //记忆个数
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 1))
                .call().entity(LoveReport.class);
        log.info("loveReport: {}", loveReport);
        return loveReport;
    }

    /**
     * 支持多轮ai对话 结构化输出
     *
     * @param message
     * @param chatId
     * @return
     */
    public String doChatWithRag(String message, String chatId) {
        String prompt = queryRewriter.doQueryRewrite(message);
        ChatResponse chatResponse = chatClient.prompt()
                .user(prompt)
                .system(LOVE_SYSTEM_PROMPT)
                //缓存id
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        //记忆个数
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 1))
                .advisors(new QuestionAnswerAdvisor(loveAppVectorStore))
                .call().chatResponse();
        String text = chatResponse.getResult().getOutput().getText();
        log.info("ai message: {}", text);
        return text;
    }

    /**
     * 支持多轮ai对话 结构化输出
     *
     * @param message
     * @param chatId
     * @return
     */
    public String doChatWithRag2(String message, String chatId) {
        //提示词重写
//        String prompt = queryRewriter.doQueryRewrite(message);

        ChatResponse chatResponse = chatClient.prompt()
                .user(message)
                .system(LOVE_SYSTEM_PROMPT)
                //缓存id
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        //记忆个数
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .advisors(VectorStoreChatMemoryAdvisor.builder(loveAppVectorStore)
                        .build())
                .advisors(GeneralRagCustomAdvisorFactory.createGeneralRagCustomAdvisor(loveAppVectorStore))
                .advisors(new MyLoggerAdvisor())
                .call().chatResponse();
        String text = chatResponse.getResult().getOutput().getText();
        log.info("ai message: {}", text);

        //手动添加缓存记忆文档  这个VectorStoreChatMemoryAdvisor这个步骤已经帮你做了
//        loveAppVectorStore.add(List.of(
//                new Document("User: " + message + "\nAI: " + text)
//        ));
        return text;
    }

    public Flux<String> doChatStream(String message, String chatId) {
        return chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        //记忆个数
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .stream().content();
    }
//
//    @Resource
//    private ToolCallbackProvider toolCallbackProvider;

    public String doChatWithMcp(String message, String chatId) {
        ChatResponse response = chatClient
                .prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                // 开启日志，便于观察效果
                .advisors(new MyLoggerAdvisor())
                .tools(allTools)
                .call()
                .chatResponse();
        String content = response.getResult().getOutput().getText();
        log.info("content: {}", content);
        return content;
    }

    public Flux<String> doChatWithLoveApp1(String message, String chatId) {
//        String writerPrompt = queryRewriter.doQueryRewrite(message);

        return chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .tools(allTools)
//                .tools(toolCallbackProvider)
                .advisors(GeneralRagCustomAdvisorFactory.createGeneralRagCustomAdvisor(loveAppVectorStore))
                .stream()
                .content();
    }

    @JsonPropertyOrder({"message", "keywords","knowledge_snippets"})
    record KeyWords(String message, List<String> keywords, List<String> knowledge_snippets) {
    }

    public Flux<String> doChatWithLoveApp(ChatDto chatDto) {
        String message = chatDto.getMessage();
        String chatId = chatDto.getChatId();
        Integer uid = chatDto.getUid();
//        String writerPrompt = queryRewriter.doQueryRewrite(message);
        KeyWords entity = chatClient.prompt()
                .system(SYSTEM_PROMPT)
                .user(message)
                .advisors(GeneralRagCustomAdvisorFactory.createGeneralRagCustomAdvisor(loveAppVectorStore))
                .call()
                .entity(KeyWords.class);


        // 优化提示词构建：使用StringBuilder和条件判断
        StringBuilder systemPromptBuilder = new StringBuilder(LOVE_SYSTEM_PROMPT);

        if (entity != null) {
            systemPromptBuilder.append("\n\n### 上下文信息 ###");

            // 添加关键词（如果存在）
            if (entity.keywords() != null && !entity.keywords().isEmpty()) {
                systemPromptBuilder.append("\n关键词：")
                        .append(String.join("、", entity.keywords()));
            }

            // 添加知识片段（如果存在）
            if (entity.knowledge_snippets() != null && !entity.knowledge_snippets().isEmpty()) {
                systemPromptBuilder.append("\n相关知识点：");
                for (String snippet : entity.knowledge_snippets()) {
                    systemPromptBuilder.append("\n- ").append(snippet);
                }
            }
        } else {
            // 可选：添加空值处理日志
             log.debug("No entity extracted for message: {}", message);
        }

        String finalSystemPrompt = systemPromptBuilder.toString();
        // 设置最大字数限制
        int MAX_TOKENS = 1000;
        AtomicInteger accumulatedLength = new AtomicInteger(0);
        StringBuilder accumulatedContent = new StringBuilder();

        return chatClient.prompt()
                .user(message)
                .advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
                        .param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
                .tools(allTools)
//                .toolContext(Map.of("userId",uid))
                .system(finalSystemPrompt )
//                .tools(toolCallbackProvider)
//                .advisors(GeneralRagCustomAdvisorFactory.createGeneralRagCustomAdvisor(loveAppVectorStore))
                .stream()
                .content()
                .takeUntil(chunk -> {
            int currentLength = accumulatedLength.get() + chunk.length();
            if (currentLength > MAX_TOKENS) {
                // 截断当前chunk并终止流
                String truncatedChunk = chunk.substring(0, MAX_TOKENS - accumulatedLength.get());
                accumulatedContent.append(truncatedChunk);
                log.warn("内容超过限制，已截断至{}字", MAX_TOKENS);
                return true;
            } else {
                accumulatedContent.append(chunk);
                accumulatedLength.addAndGet(chunk.length());
                return false;
            }
        })
                .map(chunk -> {
                    // 如果已截断，追加提示信息
                    if (accumulatedLength.get() >= MAX_TOKENS) {
                        return accumulatedContent+ "\n\n内容已根据规范自动调整";
                    }
                    return chunk;
                });
    }


}
